/*
 * pgp-decrypt.c
 *	  OpenPGP 解密。
 *
 * Copyright (c) 2005 Marko Kreen
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *	  notice, this list of条件和以下免责声明。
 * 2. Redistributions in binary form must reproduce the above copyright
 *	  notice, this list of conditions and the following disclaimer in the
 *	  文档和/或其他提供的材料与分发一起。
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 或后果
 * 损害（包括但不限于替代商品或服务的采购；丧失使用、数据或利润；或业务中断）
 * 无论因何原因以及在任何责任理论下，无论是合同、严格
 * 责任或侵权行为（包括疏忽或其他）以任何方式产生
 * 出于对本软件的使用，即使在被告知有可能发生
 * 这样的损害。
 *
 * contrib/pgcrypto/pgp-decrypt.c
 */

#include "postgres.h"

#include "mbuf.h"
#include "pgp.h"
#include "px.h"

#define NO_CTX_SIZE		0
#define ALLOW_CTX_SIZE	1
#define NO_COMPR		0
#define ALLOW_COMPR		1
#define NO_MDC			0
#define NEED_MDC		1

#define PKT_NORMAL 1
#define PKT_STREAM 2
#define PKT_CONTEXT 3

#define MAX_CHUNK (16*1024*1024)

static int fc_parse_new_len(PullFilter *fc_src, int *fc_len_p)
{
	uint8		fc_b;
	int			fc_len;
	int			fc_pkttype = PKT_NORMAL;

	GETBYTE(fc_src, fc_b);
	if (fc_b <= 191)
		fc_len = fc_b;
	else if (fc_b >= 192 && fc_b <= 223)
	{
		fc_len = ((unsigned) (fc_b) - 192) << 8;
		GETBYTE(fc_src, fc_b);
		fc_len += 192 + fc_b;
	}
	else if (fc_b == 255)
	{
		GETBYTE(fc_src, fc_b);
		fc_len = fc_b;
		GETBYTE(fc_src, fc_b);
		fc_len = (fc_len << 8) | fc_b;
		GETBYTE(fc_src, fc_b);
		fc_len = (fc_len << 8) | fc_b;
		GETBYTE(fc_src, fc_b);
		fc_len = (fc_len << 8) | fc_b;
	}
	else
	{
		fc_len = 1 << (fc_b & 0x1F);
		fc_pkttype = PKT_STREAM;
	}

	if (fc_len < 0 || fc_len > MAX_CHUNK)
	{
		px_debug("parse_new_len: weird length");
		return PXE_PGP_CORRUPT_DATA;
	}

	*fc_len_p = fc_len;
	return fc_pkttype;
}

static int fc_parse_old_len(PullFilter *fc_src, int *fc_len_p, int fc_lentype)
{
	uint8		fc_b;
	int			fc_len;

	GETBYTE(fc_src, fc_b);
	fc_len = fc_b;

	if (fc_lentype == 1)
	{
		GETBYTE(fc_src, fc_b);
		fc_len = (fc_len << 8) | fc_b;
	}
	else if (fc_lentype == 2)
	{
		GETBYTE(fc_src, fc_b);
		fc_len = (fc_len << 8) | fc_b;
		GETBYTE(fc_src, fc_b);
		fc_len = (fc_len << 8) | fc_b;
		GETBYTE(fc_src, fc_b);
		fc_len = (fc_len << 8) | fc_b;
	}

	if (fc_len < 0 || fc_len > MAX_CHUNK)
	{
		px_debug("parse_old_len: weird length");
		return PXE_PGP_CORRUPT_DATA;
	}
	*fc_len_p = fc_len;
	return PKT_NORMAL;
}

/* 返回 pkttype 或 0 在 eof 上 */
int pgp_parse_pkt_hdr(PullFilter *fc_src, uint8 *fc_tag, int *fc_len_p, int fc_allow_ctx)
{
	int			fc_lentype;
	int			fc_res;
	uint8	   *fc_p;

	/* EOF 在这里是正常的，因此我们不使用 GETBYTE */
	fc_res = pullf_read(fc_src, 1, &fc_p);
	if (fc_res < 0)
		return fc_res;
	if (fc_res == 0)
		return 0;

	if ((*fc_p & 0x80) == 0)
	{
		px_debug("pgp_parse_pkt_hdr: not pkt hdr");
		return PXE_PGP_CORRUPT_DATA;
	}

	if (*fc_p & 0x40)
	{
		*fc_tag = *fc_p & 0x3f;
		fc_res = fc_parse_new_len(fc_src, fc_len_p);
	}
	else
	{
		fc_lentype = *fc_p & 3;
		*fc_tag = (*fc_p >> 2) & 0x0F;
		if (fc_lentype == 3)
			fc_res = fc_allow_ctx ? PKT_CONTEXT : PXE_PGP_CORRUPT_DATA;
		else
			fc_res = fc_parse_old_len(fc_src, fc_len_p, fc_lentype);
	}
	return fc_res;
}

/*
 * 数据包读取器
 */
struct PktData
{
	int			type;
	int			len;
};

static int fc_pktreader_pull(void *fc_priv, PullFilter *fc_src, int fc_len,
			   uint8 **fc_data_p, uint8 *fc_buf, int fc_buflen)
{
	int			fc_res;
	struct PktData *fc_pkt = fc_priv;

	/* PKT_CONTEXT 意味着：无论有什么 */
	if (fc_pkt->type == PKT_CONTEXT)
		return pullf_read(fc_src, fc_len, fc_data_p);

	while (fc_pkt->len == 0)
	{
		/* 这是流中的最后一块 */
		if (fc_pkt->type == PKT_NORMAL)
			return 0;

		/* 流中的下一块 */
		fc_res = fc_parse_new_len(fc_src, &fc_pkt->len);
		if (fc_res < 0)
			return fc_res;
		fc_pkt->type = fc_res;
	}

	if (fc_len > fc_pkt->len)
		fc_len = fc_pkt->len;

	fc_res = pullf_read(fc_src, fc_len, fc_data_p);
	if (fc_res > 0)
		fc_pkt->len -= fc_res;

	return fc_res;
}

static void fc_pktreader_free(void *fc_priv)
{
	struct PktData *fc_pkt = fc_priv;

	px_memset(fc_pkt, 0, sizeof(*fc_pkt));
	pfree(fc_pkt);
}

static struct PullFilterOps pktreader_filter = {
	NULL, fc_pktreader_pull, fc_pktreader_free
};

/* 需要辅助函数来传递多个参数 */
int pgp_create_pkt_reader(PullFilter **fc_pf_p, PullFilter *fc_src, int fc_len,
					  int fc_pkttype, PGP_Context *fc_ctx)
{
	int			fc_res;
	struct PktData *fc_pkt = palloc(sizeof(*fc_pkt));

	fc_pkt->type = fc_pkttype;
	fc_pkt->len = fc_len;
	fc_res = pullf_create(fc_pf_p, &pktreader_filter, fc_pkt, fc_src);
	if (fc_res < 0)
		pfree(fc_pkt);
	return fc_res;
}

/*
 * 前缀检查过滤器
 * https://tools.ietf.org/html/rfc4880#section-5.7
 * https://tools.ietf.org/html/rfc4880#section-5.13
 */

static int fc_prefix_init(void **fc_priv_p, void *fc_arg, PullFilter *fc_src)
{
	PGP_Context *fc_ctx = fc_arg;
	int			fc_len;
	int			fc_res;
	uint8	   *fc_buf;
	uint8		fc_tmpbuf[PGP_MAX_BLOCK + 2];

	fc_len = pgp_get_cipher_block_size(fc_ctx->cipher_algo);
	/* 确保我们有足够的空间用于前缀 */
	if (fc_len > PGP_MAX_BLOCK)
		return PXE_BUG;

	fc_res = pullf_read_max(fc_src, fc_len + 2, &fc_buf, fc_tmpbuf);
	if (fc_res < 0)
		return fc_res;
	if (fc_res != fc_len + 2)
	{
		px_debug("prefix_init: short read");
		px_memset(fc_tmpbuf, 0, sizeof(fc_tmpbuf));
		return PXE_PGP_CORRUPT_DATA;
	}

	if (fc_buf[fc_len - 2] != fc_buf[fc_len] || fc_buf[fc_len - 1] != fc_buf[fc_len + 1])
	{
		px_debug("prefix_init: corrupt prefix");
		/* 在 pgp_decrypt() 中报告错误 */
		fc_ctx->corrupt_prefix = 1;
	}
	px_memset(fc_tmpbuf, 0, sizeof(fc_tmpbuf));
	return 0;
}

static struct PullFilterOps prefix_filter = {
	fc_prefix_init, NULL, NULL
};


/*
 * 解密过滤器
 */

static int fc_decrypt_init(void **fc_priv_p, void *fc_arg, PullFilter *fc_src)
{
	PGP_CFB    *fc_cfb = fc_arg;

	*fc_priv_p = fc_cfb;

	/* 我们需要写入某个地方，因此请求一个缓冲区 */
	return 4096;
}

static int fc_decrypt_read(void *fc_priv, PullFilter *fc_src, int fc_len,
			 uint8 **fc_data_p, uint8 *fc_buf, int fc_buflen)
{
	PGP_CFB    *fc_cfb = fc_priv;
	uint8	   *fc_tmp;
	int			fc_res;

	fc_res = pullf_read(fc_src, fc_len, &fc_tmp);
	if (fc_res > 0)
	{
		pgp_cfb_decrypt(fc_cfb, fc_tmp, fc_res, fc_buf);
		*fc_data_p = fc_buf;
	}
	return fc_res;
}

struct PullFilterOps pgp_decrypt_filter = {
	fc_decrypt_init, fc_decrypt_read, NULL
};


/*
 * MDC 哈希过滤器
 */

static int fc_mdc_init(void **fc_priv_p, void *fc_arg, PullFilter *fc_src)
{
	PGP_Context *fc_ctx = fc_arg;

	*fc_priv_p = fc_ctx;
	return pgp_load_digest(PGP_DIGEST_SHA1, &fc_ctx->mdc_ctx);
}

static void fc_mdc_free(void *fc_priv)
{
	PGP_Context *fc_ctx = fc_priv;

	if (fc_ctx->use_mdcbuf_filter)
		return;
	px_md_free(fc_ctx->mdc_ctx);
	fc_ctx->mdc_ctx = NULL;
}

static int fc_mdc_finish(PGP_Context *fc_ctx, PullFilter *fc_src, int fc_len)
{
	int			fc_res;
	uint8		fc_hash[20];
	uint8		fc_tmpbuf[20];
	uint8	   *fc_data;

	/* 不应该发生 */
	if (fc_ctx->use_mdcbuf_filter)
		return PXE_BUG;

	/* 它是 SHA1 */
	if (fc_len != 20)
		return PXE_PGP_CORRUPT_DATA;

	/* mdc_read 不应该调用 px_md_update */
	fc_ctx->in_mdc_pkt = 1;

	/* 读取数据 */
	fc_res = pullf_read_max(fc_src, fc_len, &fc_data, fc_tmpbuf);
	if (fc_res < 0)
		return fc_res;
	if (fc_res == 0)
	{
		px_debug("no mdc");
		return PXE_PGP_CORRUPT_DATA;
	}

	/* 数据包是否正常？ */
	if (fc_res != 20)
	{
		px_debug("mdc_finish: read failed, res=%d", fc_res);
		return PXE_PGP_CORRUPT_DATA;
	}

	/*
	 * 好的，我们得到了哈希，现在检查
	 */
	px_md_finish(fc_ctx->mdc_ctx, fc_hash);
	fc_res = memcmp(fc_hash, fc_data, 20);
	px_memset(fc_hash, 0, 20);
	px_memset(fc_tmpbuf, 0, sizeof(fc_tmpbuf));
	if (fc_res != 0)
	{
		px_debug("mdc_finish: mdc failed");
		return PXE_PGP_CORRUPT_DATA;
	}
	fc_ctx->mdc_checked = 1;
	return 0;
}

static int fc_mdc_read(void *fc_priv, PullFilter *fc_src, int fc_len,
		 uint8 **fc_data_p, uint8 *fc_buf, int fc_buflen)
{
	int			fc_res;
	PGP_Context *fc_ctx = fc_priv;

	/* 跳过这个过滤器？ */
	if (fc_ctx->use_mdcbuf_filter || fc_ctx->in_mdc_pkt)
		return pullf_read(fc_src, fc_len, fc_data_p);

	fc_res = pullf_read(fc_src, fc_len, fc_data_p);
	if (fc_res < 0)
		return fc_res;
	if (fc_res == 0)
	{
		px_debug("mdc_read: unexpected eof");
		return PXE_PGP_CORRUPT_DATA;
	}
	px_md_update(fc_ctx->mdc_ctx, *fc_data_p, fc_res);

	return fc_res;
}

static struct PullFilterOps mdc_filter = {
	fc_mdc_init, fc_mdc_read, fc_mdc_free
};


/*
 * 组合的 Pkt 读取器和 MDC 哈希器。
 *
 * 对于 SYMENCRYPTED_DATA_MDC 数据包的情况，其中
 * 数据部分具有“上下文长度”，这意味着
 * 数据包在父数据包结束前 22 字节结束，这很傻。
 */
#define MDCBUF_LEN 8192
struct MDCBufData
{
	PGP_Context *ctx;
	int			eof;
	int			buflen;
	int			avail;
	uint8	   *pos;
	int			mdc_avail;
	uint8		mdc_buf[22];
	uint8		buf[MDCBUF_LEN];
};

static int fc_mdcbuf_init(void **fc_priv_p, void *fc_arg, PullFilter *fc_src)
{
	PGP_Context *fc_ctx = fc_arg;
	struct MDCBufData *fc_st;

	fc_st = palloc0(sizeof(*fc_st));
	fc_st->buflen = sizeof(fc_st->buf);
	fc_st->ctx = fc_ctx;
	*fc_priv_p = fc_st;

	/* 接管 mdc_filter 的工作 */
	fc_ctx->use_mdcbuf_filter = 1;

	return 0;
}

static int fc_mdcbuf_finish(struct MDCBufData *fc_st)
{
	uint8		fc_hash[20];
	int			fc_res;

	fc_st->eof = 1;

	if (fc_st->mdc_buf[0] != 0xD3 || fc_st->mdc_buf[1] != 0x14)
	{
		px_debug("mdcbuf_finish: bad MDC pkt hdr");
		return PXE_PGP_CORRUPT_DATA;
	}
	px_md_update(fc_st->ctx->mdc_ctx, fc_st->mdc_buf, 2);
	px_md_finish(fc_st->ctx->mdc_ctx, fc_hash);
	fc_res = memcmp(fc_hash, fc_st->mdc_buf + 2, 20);
	px_memset(fc_hash, 0, 20);
	if (fc_res)
	{
		px_debug("mdcbuf_finish: MDC does not match");
		fc_res = PXE_PGP_CORRUPT_DATA;
	}
	return fc_res;
}

static void fc_mdcbuf_load_data(struct MDCBufData *fc_st, uint8 *fc_src, int fc_len)
{
	uint8	   *fc_dst = fc_st->pos + fc_st->avail;

	memcpy(fc_dst, fc_src, fc_len);
	px_md_update(fc_st->ctx->mdc_ctx, fc_src, fc_len);
	fc_st->avail += fc_len;
}

static void fc_mdcbuf_load_mdc(struct MDCBufData *fc_st, uint8 *fc_src, int fc_len)
{
	memmove(fc_st->mdc_buf + fc_st->mdc_avail, fc_src, fc_len);
	fc_st->mdc_avail += fc_len;
}

static int fc_mdcbuf_refill(struct MDCBufData *fc_st, PullFilter *fc_src)
{
	uint8	   *fc_data;
	int			fc_res;
	int			fc_need;

	/* 将可用数据放在开头 */
	if (fc_st->avail > 0 && fc_st->pos != fc_st->buf)
		memmove(fc_st->buf, fc_st->pos, fc_st->avail);
	fc_st->pos = fc_st->buf;

	/* 读取新数据 */
	fc_need = fc_st->buflen + 22 - fc_st->avail - fc_st->mdc_avail;
	fc_res = pullf_read(fc_src, fc_need, &fc_data);
	if (fc_res < 0)
		return fc_res;
	if (fc_res == 0)
		return fc_mdcbuf_finish(fc_st);

	/* 添加到缓冲区 */
	if (fc_res >= 22)
	{
		fc_mdcbuf_load_data(fc_st, fc_st->mdc_buf, fc_st->mdc_avail);
		fc_st->mdc_avail = 0;

		fc_mdcbuf_load_data(fc_st, fc_data, fc_res - 22);
		fc_mdcbuf_load_mdc(fc_st, fc_data + fc_res - 22, 22);
	}
	else
	{
		int			fc_canmove = fc_st->mdc_avail + fc_res - 22;

		if (fc_canmove > 0)
		{
			fc_mdcbuf_load_data(fc_st, fc_st->mdc_buf, fc_canmove);
			fc_st->mdc_avail -= fc_canmove;
			memmove(fc_st->mdc_buf, fc_st->mdc_buf + fc_canmove, fc_st->mdc_avail);
		}
		fc_mdcbuf_load_mdc(fc_st, fc_data, fc_res);
	}
	return 0;
}

static int fc_mdcbuf_read(void *fc_priv, PullFilter *fc_src, int fc_len,
			uint8 **fc_data_p, uint8 *fc_buf, int fc_buflen)
{
	struct MDCBufData *fc_st = fc_priv;
	int			fc_res;

	if (!fc_st->eof && fc_len > fc_st->avail)
	{
		fc_res = fc_mdcbuf_refill(fc_st, fc_src);
		if (fc_res < 0)
			return fc_res;
	}

	if (fc_len > fc_st->avail)
		fc_len = fc_st->avail;

	*fc_data_p = fc_st->pos;
	fc_st->pos += fc_len;
	fc_st->avail -= fc_len;
	return fc_len;
}

static void fc_mdcbuf_free(void *fc_priv)
{
	struct MDCBufData *fc_st = fc_priv;

	px_md_free(fc_st->ctx->mdc_ctx);
	fc_st->ctx->mdc_ctx = NULL;
	px_memset(fc_st, 0, sizeof(*fc_st));
	pfree(fc_st);
}

static struct PullFilterOps mdcbuf_filter = {
	fc_mdcbuf_init, fc_mdcbuf_read, fc_mdcbuf_free
};


/*
 * 解密单独的会话密钥
 */
static int fc_decrypt_key(PGP_Context *fc_ctx, const uint8 *fc_src, int fc_len)
{
	int			fc_res;
	uint8		fc_algo;
	PGP_CFB    *fc_cfb;

	fc_res = pgp_cfb_create(&fc_cfb, fc_ctx->s2k_cipher_algo,
						 fc_ctx->s2k.key, fc_ctx->s2k.key_len, 0, NULL);
	if (fc_res < 0)
		return fc_res;

	pgp_cfb_decrypt(fc_cfb, fc_src, 1, &fc_algo);
	fc_src++;
	fc_len--;

	pgp_cfb_decrypt(fc_cfb, fc_src, fc_len, fc_ctx->sess_key);
	pgp_cfb_free(fc_cfb);
	fc_ctx->sess_key_len = fc_len;
	fc_ctx->cipher_algo = fc_algo;

	if (pgp_get_cipher_key_size(fc_algo) != fc_len)
	{
		px_debug("sesskey bad len: algo=%d, expected=%d, got=%d",
				 fc_algo, pgp_get_cipher_key_size(fc_algo), fc_len);
		return PXE_PGP_CORRUPT_DATA;
	}
	return 0;
}

/*
 * 处理密钥数据包
 */
static int fc_parse_symenc_sesskey(PGP_Context *fc_ctx, PullFilter *fc_src)
{
	uint8	   *fc_p;
	int			fc_res;
	uint8		fc_tmpbuf[PGP_MAX_KEY + 2];
	uint8		fc_ver;

	GETBYTE(fc_src, fc_ver);
	GETBYTE(fc_src, fc_ctx->s2k_cipher_algo);
	if (fc_ver != 4)
	{
		px_debug("bad key pkt ver");
		return PXE_PGP_CORRUPT_DATA;
	}

	/*
	 * 读取 S2K 信息
	 */
	fc_res = pgp_s2k_read(fc_src, &fc_ctx->s2k);
	if (fc_res < 0)
		return fc_res;
	fc_ctx->s2k_mode = fc_ctx->s2k.mode;
	fc_ctx->s2k_count = s2k_decode_count(fc_ctx->s2k.iter);
	fc_ctx->s2k_digest_algo = fc_ctx->s2k.digest_algo;

	/*
	 * 从密码生成密钥
	 */
	fc_res = pgp_s2k_process(&fc_ctx->s2k, fc_ctx->s2k_cipher_algo,
						  fc_ctx->sym_key, fc_ctx->sym_key_len);
	if (fc_res < 0)
		return fc_res;

	/*
	 * 我们有单独的会话密钥吗？
	 */
	fc_res = pullf_read_max(fc_src, PGP_MAX_KEY + 2, &fc_p, fc_tmpbuf);
	if (fc_res < 0)
		return fc_res;

	if (fc_res == 0)
	{
		/*
		 * 不，s2k 密钥是会话密钥
		 */
		memcpy(fc_ctx->sess_key, fc_ctx->s2k.key, fc_ctx->s2k.key_len);
		fc_ctx->sess_key_len = fc_ctx->s2k.key_len;
		fc_ctx->cipher_algo = fc_ctx->s2k_cipher_algo;
		fc_res = 0;
		fc_ctx->use_sess_key = 0;
	}
	else
	{
		/*
		 * 是的，解密它
		 */
		if (fc_res < 17 || fc_res > PGP_MAX_KEY + 1)
		{
			px_debug("expect key, but bad data");
			return PXE_PGP_CORRUPT_DATA;
		}
		fc_ctx->use_sess_key = 1;
		fc_res = fc_decrypt_key(fc_ctx, fc_p, fc_res);
	}

	px_memset(fc_tmpbuf, 0, sizeof(fc_tmpbuf));
	return fc_res;
}

static int fc_copy_crlf(MBuf *fc_dst, uint8 *fc_data, int fc_len, int *fc_got_cr)
{
	uint8	   *fc_data_end = fc_data + fc_len;
	uint8		fc_tmpbuf[1024];
	uint8	   *fc_tmp_end = fc_tmpbuf + sizeof(fc_tmpbuf);
	uint8	   *fc_p;
	int			fc_res;

	fc_p = fc_tmpbuf;
	if (*fc_got_cr)
	{
		if (*fc_data != '\n')
			*fc_p++ = '\r';
		*fc_got_cr = 0;
	}
	while (fc_data < fc_data_end)
	{
		if (*fc_data == '\r')
		{
			if (fc_data + 1 < fc_data_end)
			{
				if (*(fc_data + 1) == '\n')
					fc_data++;
			}
			else
			{
				*fc_got_cr = 1;
				break;
			}
		}
		*fc_p++ = *fc_data++;
		if (fc_p >= fc_tmp_end)
		{
			fc_res = mbuf_append(fc_dst, fc_tmpbuf, fc_p - fc_tmpbuf);
			if (fc_res < 0)
				return fc_res;
			fc_p = fc_tmpbuf;
		}
	}
	if (fc_p - fc_tmpbuf > 0)
	{
		fc_res = mbuf_append(fc_dst, fc_tmpbuf, fc_p - fc_tmpbuf);
		if (fc_res < 0)
			return fc_res;
	}
	px_memset(fc_tmpbuf, 0, sizeof(fc_tmpbuf));
	return 0;
}

static int fc_parse_literal_data(PGP_Context *fc_ctx, MBuf *fc_dst, PullFilter *fc_pkt)
{
	int			fc_type;
	int			fc_name_len;
	int			fc_res;
	uint8	   *fc_buf;
	uint8		fc_tmpbuf[4];
	int			fc_got_cr = 0;

	GETBYTE(fc_pkt, fc_type);
	GETBYTE(fc_pkt, fc_name_len);

	/* 跳过名称 */
	while (fc_name_len > 0)
	{
		fc_res = pullf_read(fc_pkt, fc_name_len, &fc_buf);
		if (fc_res < 0)
			return fc_res;
		if (fc_res == 0)
			break;
		fc_name_len -= fc_res;
	}
	if (fc_name_len > 0)
	{
		px_debug("parse_literal_data: unexpected eof");
		return PXE_PGP_CORRUPT_DATA;
	}

	/* 跳过日期 */
	fc_res = pullf_read_max(fc_pkt, 4, &fc_buf, fc_tmpbuf);
	if (fc_res != 4)
	{
		px_debug("parse_literal_data: unexpected eof");
		return PXE_PGP_CORRUPT_DATA;
	}
	px_memset(fc_tmpbuf, 0, 4);

	/*
	 * 如果从返回文本的 SQL 函数调用，pgp_decrypt() 拒绝
	 * 不自我标识为文本的输入。
	 */
	if (fc_ctx->text_mode)
		if (fc_type != 't' && fc_type != 'u')
		{
			px_debug("parse_literal_data: data type=%c", fc_type);
			fc_ctx->unexpected_binary = true;
		}

	fc_ctx->unicode_mode = (fc_type == 'u') ? 1 : 0;

	/* 读取数据 */
	while (1)
	{
		fc_res = pullf_read(fc_pkt, 32 * 1024, &fc_buf);
		if (fc_res <= 0)
			break;

		if (fc_ctx->text_mode && fc_ctx->convert_crlf)
			fc_res = fc_copy_crlf(fc_dst, fc_buf, fc_res, &fc_got_cr);
		else
			fc_res = mbuf_append(fc_dst, fc_buf, fc_res);
		if (fc_res < 0)
			break;
	}
	if (fc_res >= 0 && fc_got_cr)
		fc_res = mbuf_append(fc_dst, (const uint8 *) "\r", 1);
	return fc_res;
}

/* process_data_packets 和 parse_compressed_data 互相调用 */
static int	fc_process_data_packets(PGP_Context *fc_ctx, MBuf *fc_dst,
								 PullFilter *fc_src, int fc_allow_compr, int fc_need_mdc);

static int fc_parse_compressed_data(PGP_Context *fc_ctx, MBuf *fc_dst, PullFilter *fc_pkt)
{
	int			fc_res;
	uint8		fc_type;
	PullFilter *fc_pf_decompr;
	uint8	   *fc_discard_buf;

	GETBYTE(fc_pkt, fc_type);

	fc_ctx->compress_algo = fc_type;
	switch (fc_type)
	{
		case PGP_COMPR_NONE:
			fc_res = fc_process_data_packets(fc_ctx, fc_dst, fc_pkt, NO_COMPR, NO_MDC);
			break;

		case PGP_COMPR_ZIP:
		case PGP_COMPR_ZLIB:
			fc_res = pgp_decompress_filter(&fc_pf_decompr, fc_ctx, fc_pkt);
			if (fc_res >= 0)
			{
				fc_res = fc_process_data_packets(fc_ctx, fc_dst, fc_pf_decompr,
										   NO_COMPR, NO_MDC);
				pullf_free(fc_pf_decompr);
			}
			break;

		case PGP_COMPR_BZIP2:
			px_debug("parse_compressed_data: bzip2 unsupported");
			/* 在 pgp_decrypt() 中报告错误 */
			fc_ctx->unsupported_compr = 1;

			/*
			 * 丢弃压缩数据，允许其首先影响任何
			 * MDC 摘要计算。
			 */
			while (1)
			{
				fc_res = pullf_read(fc_pkt, 32 * 1024, &fc_discard_buf);
				if (fc_res <= 0)
					break;
			}

			break;

		default:
			px_debug("parse_compressed_data: unknown compr type");
			fc_res = PXE_PGP_CORRUPT_DATA;
	}

	return fc_res;
}

static int fc_process_data_packets(PGP_Context *fc_ctx, MBuf *fc_dst, PullFilter *fc_src,
					 int fc_allow_compr, int fc_need_mdc)
{
	uint8		fc_tag;
	int			fc_len,
				fc_res;
	int			fc_got_data = 0;
	int			fc_got_mdc = 0;
	PullFilter *fc_pkt = NULL;

	while (1)
	{
		fc_res = pgp_parse_pkt_hdr(fc_src, &fc_tag, &fc_len, ALLOW_CTX_SIZE);
		if (fc_res <= 0)
			break;


		/* mdc 数据包应该是最后的 */
		if (fc_got_mdc)
		{
			px_debug("process_data_packets: data after mdc");
			fc_res = PXE_PGP_CORRUPT_DATA;
			break;
		}

		/*
		 * SYMENCRYPTED_DATA_MDC 数据包中的上下文长度需要特别
		 * 处理。
		 */
		if (fc_need_mdc && fc_res == PKT_CONTEXT)
			fc_res = pullf_create(&fc_pkt, &mdcbuf_filter, fc_ctx, fc_src);
		else
			fc_res = pgp_create_pkt_reader(&fc_pkt, fc_src, fc_len, fc_res, fc_ctx);
		if (fc_res < 0)
			break;

		switch (fc_tag)
		{
			case PGP_PKT_LITERAL_DATA:
				fc_got_data = 1;
				fc_res = fc_parse_literal_data(fc_ctx, fc_dst, fc_pkt);
				break;
			case PGP_PKT_COMPRESSED_DATA:
				if (fc_allow_compr == 0)
				{
					px_debug("process_data_packets: unexpected compression");
					fc_res = PXE_PGP_CORRUPT_DATA;
				}
				else if (fc_got_data)
				{
					/*
					 * 压缩数据必须是单独的
					 */
					px_debug("process_data_packets: only one cmpr pkt allowed");
					fc_res = PXE_PGP_CORRUPT_DATA;
				}
				else
				{
					fc_got_data = 1;
					fc_res = fc_parse_compressed_data(fc_ctx, fc_dst, fc_pkt);
				}
				break;
			case PGP_PKT_MDC:
				if (fc_need_mdc == NO_MDC)
				{
					px_debug("process_data_packets: unexpected MDC");
					fc_res = PXE_PGP_CORRUPT_DATA;
					break;
				}

				fc_res = fc_mdc_finish(fc_ctx, fc_pkt, fc_len);
				if (fc_res >= 0)
					fc_got_mdc = 1;
				break;
			default:
				px_debug("process_data_packets: unexpected pkt tag=%d", fc_tag);
				fc_res = PXE_PGP_CORRUPT_DATA;
		}

		pullf_free(fc_pkt);
		fc_pkt = NULL;

		if (fc_res < 0)
			break;
	}

	if (fc_pkt)
		pullf_free(fc_pkt);

	if (fc_res < 0)
		return fc_res;

	if (!fc_got_data)
	{
		px_debug("process_data_packets: no data");
		fc_res = PXE_PGP_CORRUPT_DATA;
	}
	if (fc_need_mdc && !fc_got_mdc && !fc_ctx->use_mdcbuf_filter)
	{
		px_debug("process_data_packets: got no mdc");
		fc_res = PXE_PGP_CORRUPT_DATA;
	}
	return fc_res;
}

static int fc_parse_symenc_data(PGP_Context *fc_ctx, PullFilter *fc_pkt, MBuf *fc_dst)
{
	int			fc_res;
	PGP_CFB    *fc_cfb = NULL;
	PullFilter *fc_pf_decrypt = NULL;
	PullFilter *fc_pf_prefix = NULL;

	fc_res = pgp_cfb_create(&fc_cfb, fc_ctx->cipher_algo,
						 fc_ctx->sess_key, fc_ctx->sess_key_len, 1, NULL);
	if (fc_res < 0)
		goto out;

	fc_res = pullf_create(&fc_pf_decrypt, &pgp_decrypt_filter, fc_cfb, fc_pkt);
	if (fc_res < 0)
		goto out;

	fc_res = pullf_create(&fc_pf_prefix, &prefix_filter, fc_ctx, fc_pf_decrypt);
	if (fc_res < 0)
		goto out;

	fc_res = fc_process_data_packets(fc_ctx, fc_dst, fc_pf_prefix, ALLOW_COMPR, NO_MDC);

out:
	if (fc_pf_prefix)
		pullf_free(fc_pf_prefix);
	if (fc_pf_decrypt)
		pullf_free(fc_pf_decrypt);
	if (fc_cfb)
		pgp_cfb_free(fc_cfb);

	return fc_res;
}

static int fc_parse_symenc_mdc_data(PGP_Context *fc_ctx, PullFilter *fc_pkt, MBuf *fc_dst)
{
	int			fc_res;
	PGP_CFB    *fc_cfb = NULL;
	PullFilter *fc_pf_decrypt = NULL;
	PullFilter *fc_pf_prefix = NULL;
	PullFilter *fc_pf_mdc = NULL;
	uint8		fc_ver;

	GETBYTE(fc_pkt, fc_ver);
	if (fc_ver != 1)
	{
		px_debug("parse_symenc_mdc_data: pkt ver != 1");
		return PXE_PGP_CORRUPT_DATA;
	}

	fc_res = pgp_cfb_create(&fc_cfb, fc_ctx->cipher_algo,
						 fc_ctx->sess_key, fc_ctx->sess_key_len, 0, NULL);
	if (fc_res < 0)
		goto out;

	fc_res = pullf_create(&fc_pf_decrypt, &pgp_decrypt_filter, fc_cfb, fc_pkt);
	if (fc_res < 0)
		goto out;

	fc_res = pullf_create(&fc_pf_mdc, &mdc_filter, fc_ctx, fc_pf_decrypt);
	if (fc_res < 0)
		goto out;

	fc_res = pullf_create(&fc_pf_prefix, &prefix_filter, fc_ctx, fc_pf_mdc);
	if (fc_res < 0)
		goto out;

	fc_res = fc_process_data_packets(fc_ctx, fc_dst, fc_pf_prefix, ALLOW_COMPR, NEED_MDC);

out:
	if (fc_pf_prefix)
		pullf_free(fc_pf_prefix);
	if (fc_pf_mdc)
		pullf_free(fc_pf_mdc);
	if (fc_pf_decrypt)
		pullf_free(fc_pf_decrypt);
	if (fc_cfb)
		pgp_cfb_free(fc_cfb);

	return fc_res;
}

/*
 * 跳过数据包内容
 */
int pgp_skip_packet(PullFilter *fc_pkt)
{
	int			fc_res = 1;
	uint8	   *fc_tmp;

	while (fc_res > 0)
		fc_res = pullf_read(fc_pkt, 32 * 1024, &fc_tmp);
	return fc_res;
}

/*
 * 期望在数据包末尾，任何数据都是错误
 */
int pgp_expect_packet_end(PullFilter *fc_pkt)
{
	int			fc_res;
	uint8	   *fc_tmp;

	fc_res = pullf_read(fc_pkt, 32 * 1024, &fc_tmp);
	if (fc_res > 0)
	{
		px_debug("pgp_expect_packet_end: got data");
		return PXE_PGP_CORRUPT_DATA;
	}
	return fc_res;
}

int pgp_decrypt(PGP_Context *fc_ctx, MBuf *fc_msrc, MBuf *fc_mdst)
{
	int			fc_res;
	PullFilter *fc_src = NULL;
	PullFilter *fc_pkt = NULL;
	uint8		fc_tag;
	int			fc_len;
	int			fc_got_key = 0;
	int			fc_got_data = 0;

	fc_res = pullf_create_mbuf_reader(&fc_src, fc_msrc);

	while (fc_res >= 0)
	{
		fc_res = pgp_parse_pkt_hdr(fc_src, &fc_tag, &fc_len, NO_CTX_SIZE);
		if (fc_res <= 0)
			break;

		fc_res = pgp_create_pkt_reader(&fc_pkt, fc_src, fc_len, fc_res, fc_ctx);
		if (fc_res < 0)
			break;

		fc_res = PXE_PGP_CORRUPT_DATA;
		switch (fc_tag)
		{
			case PGP_PKT_MARKER:
				fc_res = pgp_skip_packet(fc_pkt);
				break;
			case PGP_PKT_PUBENCRYPTED_SESSKEY:
				/* fixme: 跳过这些 */
				fc_res = pgp_parse_pubenc_sesskey(fc_ctx, fc_pkt);
				fc_got_key = 1;
				break;
			case PGP_PKT_SYMENCRYPTED_SESSKEY:
				if (fc_got_key)

					/*
					 * 理论上，可能有多个密钥，包括公钥
					 * 和对称密钥，它们都加密相同的会话密钥。
					 * 解密应该尝试每一个，然后再失败。
					 */
					px_debug("pgp_decrypt: using first of several keys");
				else
				{
					fc_got_key = 1;
					fc_res = fc_parse_symenc_sesskey(fc_ctx, fc_pkt);
				}
				break;
			case PGP_PKT_SYMENCRYPTED_DATA:
				if (!fc_got_key)
					px_debug("pgp_decrypt: have data but no key");
				else if (fc_got_data)
					px_debug("pgp_decrypt: got second data packet");
				else
				{
					fc_got_data = 1;
					fc_ctx->disable_mdc = 1;
					fc_res = fc_parse_symenc_data(fc_ctx, fc_pkt, fc_mdst);
				}
				break;
			case PGP_PKT_SYMENCRYPTED_DATA_MDC:
				if (!fc_got_key)
					px_debug("pgp_decrypt: have data but no key");
				else if (fc_got_data)
					px_debug("pgp_decrypt: several data pkts not supported");
				else
				{
					fc_got_data = 1;
					fc_ctx->disable_mdc = 0;
					fc_res = fc_parse_symenc_mdc_data(fc_ctx, fc_pkt, fc_mdst);
				}
				break;
			default:
				px_debug("pgp_decrypt: unknown tag: 0x%02x", fc_tag);
		}
		pullf_free(fc_pkt);
		fc_pkt = NULL;
	}

	if (fc_pkt)
		pullf_free(fc_pkt);

	if (fc_src)
		pullf_free(fc_src);

	if (fc_res < 0)
		return fc_res;

	/*
	 * 现在报告 prefix_init() "快速检查" 的失败，而不是
	 * 在检测时，以阻止时间攻击。pgcrypto 通常
	 * 不安全于时间攻击，但这有帮助。
	 */
	if (!fc_got_data || fc_ctx->corrupt_prefix)
		return PXE_PGP_CORRUPT_DATA;

	/*
	 * 在此阶段之前解释声称已解密数据的代码应仅报告不超过 PXE_PGP_CORRUPT_DATA 的错误。  (PXE_BUG 是可以的，只要它保持不可达。)  这确保能够选择 ciphertext 并接收相应解密错误消息的攻击者无法利用该预言者来收集有关解密密钥的线索。  参见 Serge Mister 和 Robert Zuccherato 的“对 OpenPGP 使用的 CFB 模式加密的攻击”。
	 *
	 * 文本数据或压缩数据包的第一个八位组中的问题值可能表明是简单的用户错误，例如需要调用 pgp_sym_decrypt_bytea 而不是 pgp_sym_decrypt。  不过，偶尔，这也是加密密钥与解密密钥不匹配的第一个症状。  当这是唯一遇到的问题时，报告特定错误以指导用户；否则，我们在之前会报告 PXE_PGP_CORRUPT_DATA。  密钥不匹配使其他错误变成红鲱鱼，这避免了向攻击者泄露线索。
	 */
	if (fc_ctx->unsupported_compr)
		return PXE_PGP_UNSUPPORTED_COMPR;
	if (fc_ctx->unexpected_binary)
		return PXE_PGP_NOT_TEXT;

	return fc_res;
}
